import 'dart:async';
import 'dart:io';

import 'package:dio/dio.dart';
import 'package:dio_cache_interceptor/dio_cache_interceptor.dart';
import 'package:flutter_frame/app/components/toast_widget.dart';
import 'package:flutter_frame/app/core/constans/error_code.dart';
import 'package:flutter_frame/app/core/http/result.dart';
import 'package:flutter_frame/app/core/utils/log_util.dart';
import 'package:flutter_frame/app/core/utils/user_manager.dart';
import 'package:flutter_frame/generated/json/base/json_convert_content.dart';
import 'package:flutter_frame/global.dart';
import 'package:flutter_frame/router/app_pages.dart';

import 'package:get/get.dart';

export 'result.dart';

/// http 操作类
///
/// https://github.com/flutterchina/dio/blob/master/README-ZH.md
class HttpUtil {
  factory HttpUtil() => _instance;

  HttpUtil._internal() {
    final options = BaseOptions(
      // 请求基地址,可以包含子路径
      // baseUrl: baseAliUrl,
      //连接服务器超时时间，单位是毫秒.
      connectTimeout: const Duration(seconds: 6),
      // 响应流上前后两次接受到数据的间隔，单位为毫秒。
      receiveTimeout: const Duration(seconds: 6),
      sendTimeout: const Duration(seconds: 6),
      headers: {},
      contentType: 'application/x-www-form-urlencoded',
      responseType: ResponseType.json,
    );

    dio = Dio(options);

    // if (AppEnv.isTest || AppEnv.isDebug) {
    //   // 配置代理适配器
    //   (dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (client) {
    //     if (HttpProxyUtil.isEnableProxy) {
    //       AppLogger.log('开启代理，PROXY ${HttpProxyUtil.proxyServer}');
    //       client.findProxy = (uri) {
    //         return 'PROXY ${HttpProxyUtil.proxyServer}';
    //       };
    //     }
    //     return client;
    //   };
    // }

    // 添加拦截器
    dio.interceptors.add(InterceptorsWrapper(
      onRequest: (options, handler) {
        final headers = {
          'Authorization': 'Basic ZmFuOjEyMzQ1Ng==',
          'content-type' : 'application/x-www-form-urlencoded'
        };

        final authToken = UserManager.getToken();
        if (authToken?.isBlank == false) {
          headers[HttpHeaders.authorizationHeader] = '$authToken';
        }
        options.headers = headers;
        return handler.next(options);
      },
      onResponse: (response, handler) {
        final data = response.data;
        if (data == null || (data is Map && data['code'] != 200)) {
          return handler.reject(DioException(requestOptions: response.requestOptions, response: response), true);
        }
        return handler.next(response);
      },
      onError: (DioException e, handler) {
        // Do something with response error
        final eInfo = _createErrorEntity(e);
        // Fluttertoast.showToast(msg: '${eInfo.code}   ${eInfo.message}');
        AppToast.showError('${eInfo.code}   ${eInfo.message}');
        switch (eInfo.message) {
          case '登录失效请重新登录': // 没有权限 重新登录
            // if(e.)
            _goLoginPage();
            break;
          default:
        }
        return handler.next(e);
        // 如果你想完成请求并返回一些自定义数据，可以resolve 一个`Response`,如`handler.resolve(response)`。
        // 这样请求将会被终止，上层then会被调用，then中返回的数据将是你的自定义response.
      },
    ));

    if (!Global.isRelease) {
      // 日志拦截器
      dio.interceptors.add(LogInterceptor(
        requestBody: true,
        responseBody: true,
        logPrint: (o) => AppLogger.log(o.toString()),
      )); //开启请求日志
    }

    // cacheOptions = CacheOptions(
    //   // 数据缓存3天
    //   maxStale: const Duration(days: 3),
    //   store: BackupCacheStore(
    //     // 先缓存到内存
    //     primary: MemCacheStore(),
    //     // 再缓存到磁盘
    //     secondary: HiveCacheStore(Directory.systemTemp.path),
    //   ),
    //   // 默认不开启缓存
    //   policy: CachePolicy.noCache,
    // );

    // dio.interceptors.add(DioCacheInterceptor(options: cacheOptions));
  }

  static final HttpUtil _instance = HttpUtil._internal();

  late final Dio dio;

  late final CacheOptions cacheOptions;

  /// 取消请求
  ///
  /// 同一个cancel token 可以用于多个请求，当一个cancel token取消时，所有使用该cancel token的请求都会被取消。
  void cancelRequests(CancelToken token) {
    if (!token.isCancelled) {
      token.cancel();
    }
  }

  /// token失效，去登陆页
  void _goLoginPage() {
    if (UserManager.isLoggedIn) {
      UserManager.removeUserInfo();
      Get.offNamedUntil(
        AppRoutes.authLogin,
        (route) => false,
      );
    }
  }

  /// 生成Get请求
  ///
  /// refreshCache 是否刷新缓存 默认 false, true表示忽略本地缓存, 先请求服务器, 再缓存数据
  /// enableCache 是否缓存 默认 false, true 表示优先采用本地缓存, 不存在或失效时, 才请求服务器, 再缓存数据
  HttpRequest<T> generateGetRequest<T>(
    String path, {
    Map<String, dynamic>? queryParameters,
    bool refreshCache = false,
    bool enableCache = false,
  }) {
    Options? options;

    if (refreshCache) {
      options = cacheOptions.copyWith(policy: !enableCache ? CachePolicy.refresh : CachePolicy.refreshForceCache).toOptions();
    } else if (enableCache) {
      options = cacheOptions.copyWith(policy: CachePolicy.forceCache).toOptions();
    }
    return HttpRequest<T>(DioMixin.checkOptions('GET', options).compose(
      dio.options,
      path,
      queryParameters: queryParameters,
    ));
  }

  /// 生成Post请求
  HttpRequest<T> generatePostRequest<T>(
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
  }) {
    AppLogger.devLog(queryParameters.toString());
    return HttpRequest<T>(DioMixin.checkOptions('POST', options).compose(
      dio.options,
      path,
      data: data,
      queryParameters: queryParameters,
    ));
  }

  /// 生成Put请求
  HttpRequest<T> generatePutRequest<T>(
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
  }) {
    return HttpRequest<T>(DioMixin.checkOptions('PUT', options).compose(
      dio.options,
      path,
      data: data,
      queryParameters: queryParameters,
    ));
  }

  /// 生成Patch请求
  HttpRequest<T> generatePatchRequest<T>(
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
  }) {
    return HttpRequest<T>(DioMixin.checkOptions('PATCH', options).compose(
      dio.options,
      path,
      data: data,
      queryParameters: queryParameters,
    ));
  }

  /// 生成Delete请求
  HttpRequest<T> generateDeleteRequest<T>(
    String path, {
    Map<String, dynamic>? queryParameters,
    Options? options,
  }) {
    return HttpRequest<T>(DioMixin.checkOptions('DELETE', options).compose(
      dio.options,
      path,
      queryParameters: queryParameters,
    ));
  }
}

class HttpRequest<T> {
  HttpRequest(this.requestOptions);

  final RequestOptions requestOptions;

  /// 执行请求
  Future<Result<T>> execute([CancelToken? cancelToken]) {
    if (cancelToken != null) {
      requestOptions.cancelToken = cancelToken;
    }
    return HttpUtil().dio.fetch(requestOptions).then<Result<T>>((value) {
      return _decodeData<T>(value.data['data']);
    }, onError: (error) {
      AppLogger.devLog('----$error');
      return _decodeError<T>(error);
    }).onError<Result<T>>((error, stackTrace) {
      return _decodeData(error);
    });
  }
}

Result<T> _decodeData<T>(dynamic data) {
  Pagination? pagination;
  T? res;

  // if (data is Map && Pagination.isPaginationStructure(data)) {
  //   pagination = JsonConvert.fromJsonAsT<Pagination>(data['pagination']);
  //   data = data['items'];
  // }

  final type = T.toString();

  if (data == null) {
    res = null;
  } else if (data is List && (<int>[] is T || <String>[] is T || <double>[] is T || <bool>[] is T || <dynamic>[] is T)) {
    if (<int>[] is T) {
      res = data.map<int>((dynamic e) => e as int).toList() as T;
    } else if (<String>[] is T) {
      res = data.map<String>((dynamic e) => e as String).toList() as T;
    } else if (<double>[] is T) {
      res = data.map<double>((dynamic e) => e as double).toList() as T;
    } else if (<bool>[] is T) {
      res = data.map<bool>((dynamic e) => e as bool).toList() as T;
    } else if (<dynamic>[] is T) {
      res = data as T;
    }
  } else if (type == (int).toString() ||
      type == (String).toString() ||
      type == (double).toString() ||
      type == (bool).toString() ||
      type == dynamic.toString()) {
    res = data as T;
  } else {
    try {
      res = JsonConvert.fromJsonAsT<T>(data);
    } catch (e) {
      return Result<T>.fail(-1, '解析数据发生错误');
    }
  }
  return Result<T>.success(res, pagination: pagination);
}

Result<T> _decodeError<T>(dynamic error) {
  if (error is DioException) {
    final data = error.response?.data;
    if (data is Map) {
      int code;
      String message;
      if(data.containsKey('code')){
         code = data['code'] != null
            ? (data['code'] is String ? (int.tryParse(data['code'] as String) ?? ErrorCodeConstants.unknown) : data['code'] as int)
            : ErrorCodeConstants.unknown;message = data['message']?.toString() ?? '未知错误';
        return Result<T>.fail(code, message, errorData: data['data']);
      } else if(data.containsKey('body')) {
        final body = data['body'];
        if(body is Map && body.containsKey('code')){
          code = body['code'] != null
              ? (body['code'] is String ? (int.tryParse(body['code'] as String) ?? ErrorCodeConstants.unknown) : body['code'] as int)
              : ErrorCodeConstants.unknown;
          message = body['message']?.toString() ?? '未知错误';
          return Result<T>.fail(code, message, errorData: data);
        }
      }
    }
    final eInfo = _createErrorEntity(error);
    return Result<T>.fail(eInfo.code, eInfo.message);
  } else {
    return Result.fail(ErrorCodeConstants.unknown, '未知错误');
  }
}

// error统一处理 错误信息
_ErrorEntity _createErrorEntity(DioException error) {
  switch (error.type) {
    case DioExceptionType.cancel:
      // 取消请求不弹toast了。 -2 表示请求取消.
      return _ErrorEntity(code: ErrorCodeConstants.cancel, message: '请求被取消');
    case DioExceptionType.connectionTimeout:
      return _ErrorEntity(code: ErrorCodeConstants.connectTimeout, message: '连接超时');
    case DioExceptionType.sendTimeout:
      return _ErrorEntity(code: ErrorCodeConstants.sendTimeout, message: '请求超时');
    case DioExceptionType.receiveTimeout:
      return _ErrorEntity(code: ErrorCodeConstants.receiveTimeout, message: '响应超时');
    case DioExceptionType.badResponse:
      {
        try {
          final errCode = error.response?.statusCode;
          switch (errCode) {
            case 400:
              return _ErrorEntity(code: errCode!, message: '请求语法错误');
            case 401:
              return _ErrorEntity(code: errCode!, message: '登录失效请重新登录');
            case 403:
              return _ErrorEntity(code: errCode!, message: '服务器拒绝执行');
            case 404:
              return _ErrorEntity(code: errCode!, message: '无法连接服务器');
            case 405:
              return _ErrorEntity(code: errCode!, message: '请求方法被禁止');
            case 500:
              return _ErrorEntity(code: errCode!, message: '服务器内部错误');
            case 502:
              return _ErrorEntity(code: errCode!, message: '无效的请求');
            case 503:
              return _ErrorEntity(code: errCode!, message: '服务器故障');
            case 505:
              return _ErrorEntity(code: errCode!, message: '不支持HTTP协议请求');
            case 1100:
              return _ErrorEntity(code: errCode!, message: error.message.toString());
            default:
              return _ErrorEntity(
                code: errCode ?? ErrorCodeConstants.unknown,
                message: error.response?.statusMessage ?? '未知错误',
              );
          }
        } on Exception catch (_) {
          return _ErrorEntity(code: ErrorCodeConstants.unknown, message: '未知错误');
        }
      }
    default:
      return _ErrorEntity(code: int.tryParse(error.response!.data['code'].toString()) ?? 0, message: error.response!.data['message'].toString());
  }
}

// 异常处理
class _ErrorEntity implements Exception {
  _ErrorEntity({required this.code, required this.message});

  int code;
  String message;

  @override
  String toString() {
    return 'Exception: code $code, $message';
  }
}
